package com.miao.im.support.delayqueue;

import lombok.Getter;
import lombok.Setter;

import java.util.Objects;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Auther: miaoguoxin
 * @Date: 2021/3/16 16:03
 * @Description:
 */
@Getter
public class DelayMessageTask<T extends Runnable> implements Delayed {
    /**消息序号*/
    private int msgSeq;
    /**客户端的用户id*/
    private String userId;
    /**消息内容  */
    @Setter
    private T task;
    /** 延迟时长，这个是必须的属性因为要按照这个判断延时时长。*/
    private long time;
    /**重试次数*/
    private AtomicInteger retryCount = new AtomicInteger();
    /**标记该任务已被移除，防止A B线程同时进行时，A线程移除的时候，B线程刚好重新添加任务的情况*/
    private AtomicBoolean removed = new AtomicBoolean(false);

    public DelayMessageTask(int msgSeq, String userId) {
        this.msgSeq = msgSeq;
        this.userId = userId;
    }

    public DelayMessageTask(int msgSeq, String userId, long time, TimeUnit unit) {
        this(msgSeq, userId);
        this.time = TimeUnit.NANOSECONDS.convert(time, unit) + System.nanoTime();
    }

    public DelayMessageTask(int msgSeq, String userId, T task, long time, TimeUnit unit) {
        this(msgSeq, userId, time, unit);
        this.task = task;
    }

    public int incAndGetRetryCount() {
        return retryCount.incrementAndGet();
    }

    /**
     * 标记任务已被移除
     * @author miaoguoxin
     * @date 2021/3/17
     */
    public boolean markRemoved() {
        return this.removed.compareAndSet(false, true);
    }

    /**
     * 任务是否被移除队列
     * @author miaoguoxin
     * @date 2021/3/17
     */
    public boolean hasRemoved() {
        return this.removed.compareAndSet(true, true);
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(this.time - System.nanoTime(), TimeUnit.NANOSECONDS);
    }

    @Override
    public int compareTo(Delayed delayed) {
        DelayMessageTask<?> other = (DelayMessageTask<?>) delayed;
        long diff = time - other.time;
        if (diff > 0) {
            return 1;
        } else if (diff < 0) {
            return -1;
        } else {
            return 0;
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        DelayMessageTask<?> that = (DelayMessageTask<?>) o;
        return msgSeq == that.msgSeq &&
                Objects.equals(userId, that.userId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(msgSeq, userId);
    }
}
